home *** CD-ROM | disk | FTP | other *** search
- PROGRAM KERMIT;
- (* AN IMPLEMENTATION OF KERMIT FOR THE IBM 9000, THIS IS A BASIC SEND ONLY *)
- (* KERMIT DESIGNED FOR SHORT TRANSFERS OVER A NULL MODEM LINE, NO ATTEMPT AT *)
- (* TERMINAL EMULATION WAS ATTEMPTED. --- WARNING, THIS SOURCE CODE WAS TYPED IN *)
- (* BY HAND AS THE ORIGINAL SOURCE FILE WAS UNAVAILABLE, THEIR MIGHT BE TYPOS *)
- (* 2ND WARNING, THIS IS THE FIRST PASCAL PROGRAM I EVER WROTE *)
- (* 3RD WARNING, WHEN LINKING THIS PROGRAM BE SURE TO ALLOCATE LESS THEN THE *)
- (* DEFAULT STACK SPACE 28K IS FINE, THIS WILL ENABLE THIS PROGRAM TO RUN ON *)
- (* COMPUTERS WITH SMALLER RAM SIZES *)
-
- (* AUTHOR: GLENN R. HOWES --> HOWES@BERT.CHEM.WISC.EDU *)
- (* DATE: MAY, 1990 *)
- USES
- SYSTEM_LIBRARY;
-
- TYPE
- PACKET = STRING[82];
- PKTPNT = ^PACKET;
- BUFFER = PACKED ARRAY[1..512] OF CHAR;
- BUFFPNT = ^BUFFER;
- SMPACKET = STRING[1];
- VAR
- (******************** GLOBAL VARIABLES ***********************)
- IRFILE: TEXT; (* UNTYPED (NON-TEXT) FILE DESCRIPTOR FOR INTERNAL USE *)
- IRBUFFER: BUFFER; (* READ 512 BYTES FROM FILE AT ONCE *)
- IRPNT: BUFFPNT;
- BLOCK: INTEGER; (* INDEX TO KEEP TRACK OF WHICH FILE BLOCK IS BEING ACCESSED *)
- ENDOFBLOCK: BOOLEAN; (* FLAG TO INDICATE ALL 512 BYTES OF A BLOCK HAVE BEEN USED *)
- ENDFILE: BOOLEAN; (* FLAG TO INDICATE THE END OF THE FILE HAS BEEN REACHED *)
- BLOCKLENGTH: INTEGER;
- IRINDEX, BUFFINDEX: INTEGER;
- PACKETNUM: INTEGER; (* INDEX TO KEEP TRACK OF HOW MANY PACKETS HAVE BEEN SENT *)
- FILENAME: STRING[100];
- S, F, D, Z, B, Y, N, E: CHAR; (* ALL THE DIFFERENT KERMIT PACKET TYPES *)
- QUIT: BOOLEAN;
- GSPACKET, GRPACKET: PACKET; (* GLOBAL SEND AND RECEIVE PACKETS *)
- SERIAL0: INTEGER; (* DEVICE LUN # FOR SERIAL PORT 1 *)
- SERIALTEXT:FILE; (* USED IN INITIALIZANG SERIAL DRIVER *)
-
- (******************* ENCODING ROUTINES *********************)
- FUNCTION TOCHAR (X: INTEGER): CHAR;
- VAR
- MYCHAR: CHAR;
- BEGIN
- X := X + 32;
- MYCHAR := CHR(X);
- TOCHAR := MYCHAR;
- END;
- FUNCTION UNCHAR (MYCHAR: CHAR): INTEGER;
- VAR
- X: INTEGER;
- BEGIN
- X := ORD(MYCHAR);
- X := X - 32;
- UNCHAR := X;
- END;
- FUNCTION CTL (MYCHAR: CHAR): CHAR; (* THIS IS A HACK VERSION OF ORD(CHAR) X0R 64 *)
- VAR
- X: INTEGER;
- I: INTEGER;
- J: INTEGER;
- BEGIN
- X := ORD(MYCHAR);
- I := X OR 64;
- J := X AND 64;
- X := I - J;
- CTL := CHR(X);
- END;
- FUNCTION FIND_CHECK_SUM (MYPACKET: PACKET; MYLENGTH: INTEGER): CHAR;
- VAR
- SUM, I, RAWCHECK: INTEGER;
- BEGIN
- SUM := 0;
- FOR I := 1 TO (MYLENGTH) DO (* SUM OF FIELD 2 THROUGH FIELD CHECK -1*)
- BEGIN
- SUM := SUM + ORD(MYPACKET[I]);
- END;
- RAWCHECK := (SUM + ((SUM AND 192) DIV 64)) AND 63;
- FIND_CHECK_SUM := TOCHAR(RAWCHECK);
- END;
- FUNCTION CONTROL_ENCODE (MYCHAR: CHAR): BOOLEAN;
- VAR
- TEMPBYTE: CHAR;
- CHARINT: INTEGER;
- TEMPINT: INTEGER;
- BEGIN
- CHARINT := ORD(MYCHAR);
- TEMPINT := CHARINT AND 127;
- IF ((TEMPINT < 32) OR (TEMPINT = 127)) THEN
- CONTROL_ENCODE := TRUE;
- END;
- (******************* FILE ROUTINES **********************)
- FUNCTION OPEN_FILE: BOOLEAN;
- BEGIN
- (*$I-*)
- RESET(IRFILE, FILENAME);
- (*$I+*)
- IF IORESULT = 0 THEN
- OPEN_FILE := TRUE
- ELSE
- BEGIN
- WRITELN('BAD FILENAME, OR OTHER ERROR: TRY AGAIN');
- OPEN_FILE := FALSE;
- END;
- END;
- PROCEDURE GET_FILE_NAME;
- BEGIN
- IF ARGC > 0 THEN
- BEGIN
- FILENAME := ARGV[1]^;
- ARGC := 0;
- END
- ELSE
- BEGIN
- WRITE('FILENAME (OR Q TO QUIT):');
- READLN(FILENAME);
- END;
- END;
- PROCEDURE GET_N_CHECK_FILE;
- VAR
- GOODFILE: BOOLEAN;
- BEGIN
- GOODFILE := FALSE;
- REPEAT
- GET_FILE_NAME;
- IF FILENAME[1] = 'Q' THEN
- BEGIN
- QUIT := TRUE;
- GOODFILE := TRUE;
- END
- ELSE
- GOODFILE := OPEN_FILE;
- UNTIL GOODFILE = TRUE;
- END;
-
- (********************** SERIAL PORT INTERACTION ROUTINES **************)
- PROCEDURE OPEN_SERIAL0;
- VAR
- CTLPACKET: ARRAY[1..15] OF INTEGER;
- ERROR: INTEGER;
- BEGIN
- RESET(SERIALTEXT, '#SER00');
- SERIAL0 := GETLUN(@SERIALTEXT);
- CTLPACKET[1] := 4;
- CTLPACKET[2] := $0064; (* 5 SECOND TIMEOUT *)
- CTLPACKET[3] := 6;
- CTLPACKET[4] := $00C8; (* 10 SECOND RECEIVE TIMEOUT *)
- CTLPACKET[5] := 20;
- CTLPACKET[6] := 13; (* 9600 BAUD *)
- CTLPACKET[7] := 0;
- SYSFUNC(SERIAL0, @CTLPACKET, ERROR);
- IF ERROR <> 0 THEN
- WRITELN('ERROR NUMBER ', ERROR);
- END;
- PROCEDURE CLOSE_SERIAL0;
- BEGIN
- CLOSE(SERIALTEXT);
- END
- PROCEDURE SEND_PACKET;
- VAR
- ERROR: INTEGER;
- PAKSIZE: INTEGER;
- BEGIN
- PAKSIZE:
- UNCHAR(GSPACKET[1]) + 3;
- SWRITE(SERIAL0, @GSPACKET, PAKSIZE, 0, 0, 0, ERROR);
- IF ERROR <> 0 THEN
- WRITELN('ERROR IN SERIAL PORT: ', ERROR);
- END;
- FUNCTION PACKET_RECEIVE: BOOLEAN;
- VAR
- ERROR: INTEGER;
- TEMPC: SMPACKET;
- I: INTEGER;
- LENGTH: INTEGER;
- BEGIN
- REPEAT
- SREAD(SERIAL0, @TEMPC, 1, 0, 0, 0, ERROR);
- GRPACKET[0] := TEMPC[0];
- UNTIL GRPACKET[0] = CHR(1); (* UNTIL WE SEE THE START OF PACKET SYMBOL *)
- SREAD(SERIAL0, @TEMPC, 1, 0, 0, 0, ERROR);
- GRPACKET[1] := TEMPC[0];
- LENGTH := UNCHAR(TEMPC[0]) + 2;
- FOR I := 2 TO LENGTH DO
- BEGIN
- SREAD(SERIAL0, @TEMPC, 1, 0, 0, 0, ERROR);
- GRPACKET[I] := TEMPC[0];
- END;
- IF ERROR <> 0 THEN
- BEGIN
- WRITELN('ERROR IN RECEIVING: ', ERROR);
- PACKET_RECEIVE := FALSE;
- END
- ELSE
- PACKET_RECEIVE := TRUE;
- END;
-
- (****************** MAKE PACKET ROUTINES ************* *)
- PROCEDURE MAKE_INIT_PACKET;
- BEGIN
- GSPACKET[1] := TOCHAR(9); (* LENGTH OF REMAINING PACKET *)
- GSPACKET[2] := TOCHAR(0); (* THIS IS THE FIRST PACKET *)
- GSPACKET[3] := S; (* THIS IS TYPE S *)
- GSPACKET[4] := TOCHAR(80); (* MAX PACKET LENGTH IS 80 *)
- GSPACKET[5] := TOCHAR(5); (* 5 SECOND TIMEOUT *)
- GSPACKET[6] := TOCHAR(0); (* NO PADDING USED *)
- GSPACKET[7] := '@'; (* PADDING SYMBOL, DOESN'T MATTER ANYWAY *)
- GSPACKET[8] := TOCHAR(13); (* END OF LINE CHARACTER *)
- GSPACKET[9] := '#'; (* THE CONTROL PREFIX FOR CONTROL CHARACTER ENCODING *)
- GSPACKET[10] := FIND_CHECK_SUM(GSPACKET, 9);
- GSPACKET[11] := CHR(13); (* END OF LINE IS A CARRIAGE RETURN *)
- END;
- PROCEDURE MAKE_FILE_HEADER;
- VAR
- STLENGTH: INTEGER;
- PKLENGTH: INTEGER;
- I: INTEGER;
- SEQUENCE: INTEGER;
- BEGIN
- STLENGTH := LENGTH(FILENAME);
- PKLENGTH := STLENGTH + 3;
- GSPACKET[1] := TOCHAR(PKLENGTH);
- GSPACKET[3] := F;
- SEQUENCE := PACKETNUM MOD 64;
- GSPACKET[2] := TOCHAR(SEQUENCE);
- FOR I := 1 TO (STLENGTH) DO
- BEGIN
- GSPACKET[(I + 3)] := FILENAME[I];
- END;
- GSPACKET[(PKLENGTH + 1)] := FIND_CHECK_SUM(GSPACKET, PKLENGTH);
- GSPACKET[PKLENGTH + 2] := CHR(13);
- WRITELN('MADE HEADER');
- END;
-
- PROCEDURE MAKE_DATA_PACKET;
- VAR
- PAKSIZE: INTEGER;
- TEMPCHAR: CHAR;
- DONE: BOOLEAN;
- SEQUENCE: INTEGER;
- INDEX: INTEGER;
- SUM: INTEGER;
- RAWCHECK: INTEGER;
- BEGIN
- PAKSIZE := 5;
- SEQUENCE := PACKETNUM MOD 64;
- GSPACKET[2] := TOCHAR(SEQUENCE);
- SUM := ORD(GSPACKET[2]);
- INDEX := 4;
- REPEAT
- TEMPCHAR := IRBUFFER[IRINDEX];
- IF CONTROL_ENCODE(TEMPCHAR) = TRUE THEN
- BEGIN
- TEMPCHAR := CTL(TEMPCHAR);
- GSPACKET[INDEX] := '#';
- INDEX := INDEX + 1;
- PAKSIZE := PAKSIZE + 1;
- SUM := SUM + 35; (* ASCII NUMBER OF '#' SIGN *)
- END
- ELSE IF TEMPCHAR = '#' THEN
- BEGIN
- GSPACKET[INDEX] := '#';
- INDEX := INDEX + 1;
- PAKSIZE := PAKSIZE + 1;
- SUM := SUM + 35;
- END;
- GSPACKET[INDEX] := TEMPCHAR;
- INDEX := INDEX + 1;
- PAKSIZE := PAKSIZE + 1;
- IRINDEX := IRINDEX + 1;
- SUM := SUM + ORD(TEMPCHAR);
- IF IRINDEX = (BLOCKLENGTH + 1) THEN
- ENDOFBLOCK := TRUE;
- UNTIL ((ENDOFBLOCK = TRUE) OR (PAKSIZE >= 80));
- GSPACKET[1] := TOCHAR((INDEX - 1));
- SUM := SUM + ORD(GSPACKET[1]) + ORD(D); (* ADDING THE LENGTH AND THE TYPE *)
- RAWCHECK := (SUM + ((SUM AND 192) DIV 64)) AND 63;
- GSPACKET[INDEX] := TOCHAR(RAWCHECK);
- GSPACKET[(INDEX + 1)] := CHR(13);
- END;
- PROCEDURE MAKE_EOF;
- VAR
- SEQUENCE: INTEGER;
- BEGIN
- GSPACKET[3] := Z;
- GSPACKET[1] := TOCHAR(3);
- SEQUENCE := PACKETNUM MOD 64;
- GSPACKET[2] := TOCHAR(SEQUENCE);
- GSPACKET[4] := FIND_CHECK_SUM(GSPACKET, 3);
- GSPACKET[5] := CHR(13);
- END;
- PROCEDURE MAKE_END_OF_TRANS;
- VAR
- SEQUENCE: INTEGER;
- BEGIN
- GSPACKET[3] := B;
- GSPACKET[1] := TOCHAR(3);
- SEQUENCE := PACKETNUM MOD 64;
- GSPACKET[2] := TOCHAR(SEQUENCE);
- GSPACKET[4] := FIND_CHECK_SUM(GSPACKET, 3);
- GSPACKET[5] := CHR(13);
- END;
- (********************* INITIALIZATION ROUTINES ***************)
- PROCEDURE INITPACKTYPES;
-
- BEGIN
- S := 'S';
- F := 'F';
- D := 'D';
- Z := 'Z';
- B := 'B';
- Y := 'Y';
- N := 'N';
- E := 'E';
- GRPACKET := ' ';
- GSPACKET := ' ';
- END;
- (********************** MISCELANEOUS ROUTINES *************)
- PROCEDURE DISPLAY_INSTRUCTIONS;
- VAR
- TEMPSTRING: STRING[25];
- BEGIN
- WRITELN('MAKE SURE THE OTHER COMPUTER IS READY TO RECEIVE. ');
- WRITELN('HIT RETURN TO PROCEED');
- READLN(TEMPSTRING);
- END;
- PROCEDURE READ_FILE_BLOCK;
- VAR
- TEMPCHAR: CHR;
- BEGIN
- BLOCKLENGTH := 0;
- REPEAT
- ENDFILE := EOF(IRFILE);
- IF ENDFILE = FALSE THEN
- BEGIN
-
- IF EOLN(IRFILE) = FALSE THEN
- BEGIN
- BLOCKLENGTH := BLOCKLENGTH + 1;
- READ(IRFILE, TEMPCHAR);
- IRBUFFER[BLOCKLENGTH] := TEMPCHAR;
- END
- ELSE
- BEGIN
- BLOCKLENGTH := BLOCKLENGTH + 1;
- READ(IRFILE, TEMPCHAR);
- IRBUFFER[BLOCKLENGTH] := CHR(13);
- END;
- END;
- UNTIL ((ENDFILE = TRUE) OR (BLOCKLENGTH = 512))
- END;
- (************************* DECISION MAKING ROUTINES ************)
- PROCEDURE RECEIVE_AND_CONFIRM;
- VAR
- CHECKCHAR: CHAR;
- PAKLENGTH: INTEGER;
- SEQUENCE: INTEGER;
- SEQCHAR: CHAR;
- CONFIRMED: BOOLEAN;
- BEGIN
- CONFIRMED := TRUE;
- REPEAT
- SEND_PACKET;
- IF ((PACKET_RECEIVE = TRUE) AND (GRPACKET[3] = Y)) THEN
- BEGIN
- PAKLENGTH := UNCHAR(GRPACKET[1]);
- CHECKCHAR := FIND_CHECK_SUM(GRPACKET, PAKLENGTH);
- SEQUENCE := PACKETNUM MOD 64;
- SEQCHAR := TOCHAR(SEQUENCE);
- IF ((CHECKCHR <> GRPACKET[PAKLENGTH + 1]) OR (SEQCHAR <> GRPACKT[2])) THEN
- BEGIN
- CONFIRMED := FALSE;
- END
- ELSE
- CONFIRMED := TRUE;
- END
- ELSE
- BEGIN
- WRITELN('FALSE');
- CONFIRMED := FALSE;
- IF GRPACKET[3] = E THEN
- WRITELN('FATAL ERROR');
- END;
- UNTIL CONFIRMED = TRUE;
- END;
- PROCEDURE INITIATE_TRANSFER;
- BEGIN
- BLOCK := 0; (* WE ARE STARTING TO READ THE FILE FROM DISK *)
- READ_FILE_BLOCK;
- IF BLOCKLENGTH > 0 THEN
- BEGIN
- MAKE_INIT_PACKET;
- RECEIVE_AND_CONFIRM;
- PACKETNUM := 1;
- MAKE_FILE_HEADER;
- RECEIVE_AND_CONFIRM;
- PACKETNUM := 2;
- IRPNT := @IRBUFFER;
- REPEAT
- ENDOFBLOCK := FALSE;
- IRINDEX := 1;
- GSPACKET[3] := D;
- REPEAT
- MAKE_DATA_PACKET;
- WRITE('.');
- RECEIVE_AND_CONFIRM;
- PACKETNUM := PAKETNUM + 1;
-
- UNTIL ENDOFBLOCK = TRUE;
- WRITELN('+');
- BLOCK := BLOCK + 1;
- READ_FILE_BLOCK;
- UNTIL BLOCKLENGTH = 0; (* END OF FILE *)
- MAKE_EOF;
- WRITELN('END OF FILE SENT');
- RECEIVE_AND_CONFIRM;
- END
- ELSE
- WRITELN('NO APPARENT FILE TO READ');
- END;
- (******************** MAIN PROGRAM ******************)
- BEGIN
- INITPACKTYPES;
- GSPACKET[0] := CHR(1);
- OPEN_SERIAL0;
- QUIT := FALSE;
- GET_N_CHECK_FILE;
- WHILE QUIT = FALSE DO
- BEGIN
- DISPLAY_INSTRUCTIONS;
- PACKETNUM := 0;
- INITIATE_TRANSFER;
- GET_N_CHECK_FILE;
- END;
- CLOSE_SERIAL0;
- END.
-
-